package com.smp.service.impl;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import com.smp.service.FutureTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author: fangxiaoyu
 * @date: 2021/7/1
 * @description:
 **/
@Slf4j
@Service
public class FutureTaskServiceImpl implements FutureTaskService {

    private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNamePrefix("Future-Task-Service").build();

    @Override
    public String eatTea() throws ExecutionException, InterruptedException {
        ExecutorService executorService = new ThreadPoolExecutor(2, 2, 8, TimeUnit.SECONDS, new LinkedBlockingDeque<>());

        FutureTask<String> t2Task = new FutureTask<>(new T2Task());
        FutureTask<String> t1Task = new FutureTask<>(new T1Task(t2Task));

        executorService.submit(t1Task);
        executorService.submit(t2Task);

        executorService.shutdown();
        return t1Task.get();
    }

    @Override
    public String eatTea2() throws InterruptedException {
        ExecutorService executorService = new ThreadPoolExecutor(
                5,
                10,
                8,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(5),
                namedThreadFactory);

        List<Callable<String>> futureTaskList = new ArrayList<>();
        for (int i = 1; i <= 5; i++) {
            futureTaskList.add(new T2Task(i));
        }
        List<Future<String>> futures = executorService.invokeAll(futureTaskList, 10, TimeUnit.SECONDS);
        StringBuffer teas = new StringBuffer();
        futures.stream().forEach(future -> {
            try {
                String tea = future.get();
                teas.append(tea).append("|");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });
        executorService.shutdown();
        return teas.toString();
    }

    @Override
    public String eatTea3() throws InterruptedException {
        ExecutorService executorService = new ThreadPoolExecutor(
                5,
                10,
                8,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(5),
                namedThreadFactory);

        List<Callable<String>> callables = new ArrayList<>();
        for (int i = 0; i <= 5; i++) {
            int finalI = i;
            Callable<String> callable = () -> {
                log.info("执行一个异步操作");
                TimeUnit.SECONDS.sleep(2);
                String result = "彩虹糖-" + finalI;
                log.info("【{}】", result);
                return result;
            };
            callables.add(callable);
        }
        List<Future<String>> futures = executorService.invokeAll(callables);
        StringBuffer stringBuffer = new StringBuffer();
        try {
            futures.stream().forEach(future -> {
                try {
                    stringBuffer.append(future.get()).append("|");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            });
        } finally {
            executorService.shutdown();
        }
        return stringBuffer.toString();
    }

    static class T1Task implements Callable<String> {

        private FutureTask<String> t2Task;

        public T1Task(FutureTask<String> t2Task) {
            this.t2Task = t2Task;
        }

        @Override
        public String call() throws Exception {
            log.info("T1：洗茶壶...");
            TimeUnit.SECONDS.sleep(1);

            log.info("T1：烧开水...");
            TimeUnit.SECONDS.sleep(2);
            // 判断T2是否执行完
            while (!t2Task.isDone()) {
                log.info("等茶叶...");
                TimeUnit.SECONDS.sleep(1);
            }

            String tea = t2Task.get();
            log.info("T1：拿到T2的{}，开始泡茶", tea);
            return "T1：上茶！！！";
        }
    }

    static class T2Task implements Callable<String> {

        private Integer index;

        public T2Task() {
        }

        public T2Task(Integer index) {
            this.index = index;
        }

        @Override
        public String call() throws Exception {
            log.info("T{}：洗茶壶...", index == null ? "2" : index);
            TimeUnit.SECONDS.sleep(1);

            log.info("T{}：洗茶杯...", index == null ? "2" : index);
            TimeUnit.SECONDS.sleep(2);

            log.info("T{}：拿茶叶...", index == null ? "2" : index);
            TimeUnit.SECONDS.sleep(1);
            return "菊花茶";
        }
    }
}
